// gopath 下 github.com 全克隆脚本
package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"sync"
	"syscall"
)

var FilesLen int

func main() {
	num := runtime.NumCPU()
	runtime.GOMAXPROCS(num - 2)
	fmt.Println("Cpu 核心数量：", num)
	fmt.Printf("Info: Start\n")

	ignorePath := []string{".git"}

	var files []string
	//var path = "E:\\GoPath\\src"
	var path = "E:\\Study\\Golang"
	err := GetAllFile(path, &files, &ignorePath)
	if err != nil {
		fmt.Printf(err.Error() + "\n")
	}

	FilesLen = len(files)
	fmt.Printf("文件名列表总数:%v\n", len(files))
	ch := make(chan int, 8)
	GetClone(files, ch)
	//GoGet(files, ch)
	End(ch, Isend)
	fmt.Printf("Info: End\n")
	//os.Chmod()

}
func GoGet(files []string, ch chan<- int) {
	for i, file := range files {
		fmt.Printf("\n第%v个\n", i)
		filepath := file[14 : len(file)-1] //E:\GoPath\src\github.com\99designs\httpsignatures-go
		fmt.Printf("\n第%v个\n", filepath)
		R.Lock()
		go GoGetCmd(filepath, ch, i)
		if jishuqi >= FilesLen {
			Isend = true
			break
		}
		R.Unlock()
	}
}
func GoGetCmd(file string, ch chan<- int, i int) {
	fmt.Print("开始", file, "\n")
	cmd := exec.Command("cmd")
	in := bytes.NewBuffer(nil)
	cmd.Stdin = in //绑定输入
	var out bytes.Buffer
	var stderr bytes.Buffer
	stdout, err := cmd.StdoutPipe()
	cmd.Stdout = &out //绑定输出
	cmd.Stderr = &stderr
	go func() {
		// start stop restart
		in.WriteString("go get " + file + "\n") //写入你的命令，可以有多行，"\n"表示回车
	}()
	if err := cmd.Start(); err != nil {
		fmt.Println(fmt.Sprint(err) + ":" + stderr.String())
	}
	reader := bufio.NewReader(stdout)
	for {
		line, err2 := reader.ReadString('\n')
		if err2 != nil || io.EOF == err2 {
			break
		}
		fmt.Println(line)
	}
	//err := cmd.Start()
	//if err != nil {
	//	log.Fatal(err)
	//}
	err = cmd.Wait()
	if err != nil {
		log.Printf("Command finished with error: %v", err)
	}
	rt := out.String() //mahonia.NewDecoder("gbk").ConvertString(out.String()) //
	fmt.Println(rt)

	if strings.ContainsAny(rt, "成功") {
		fmt.Printf("{\"msg\":\"%s\"}", "操作成功")
	} else {
		fmt.Printf("{\"msg\":\"%s\"}", rt)
	}
	fmt.Print("结束\n")
	jishuqi += 1
	fmt.Println("计数器：", jishuqi)
	ch <- i
}

func End(ch chan int, isend bool) {
	for {
		select {
		case j := <-ch:
			fmt.Printf("\n第%v个结束\n", j)
			if isend {
				break
			}
		}
	}
}

func GetClone(files []string, ch chan<- int) {
	for i, file := range files {
		fmt.Printf("\n第%v个\n", i)
		R.Lock()
		go GitClone(file, ch, i)
		if jishuqi >= FilesLen {
			Isend = true
			break
		}
		R.Unlock()
	}
}

var R sync.Mutex
var Isend bool = false
var jishuqi int = 0

func GitClone(file string, ch chan<- int, i int) {
	fmt.Print("开始", file, "\n")
	cmd := exec.Command("cmd")
	in := bytes.NewBuffer(nil)
	cmd.Stdin = in //绑定输入
	var out bytes.Buffer
	var stderr bytes.Buffer
	stdout, err := cmd.StdoutPipe()
	cmd.Stdout = &out //绑定输出
	cmd.Stderr = &stderr
	cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
	go func() {
		// start stop restart
		in.WriteString("cd " + file + "&& git pull origin master" + "\n") //写入你的命令，可以有多行，"\n"表示回车
	}()
	if err := cmd.Start(); err != nil {
		fmt.Println(fmt.Sprint(err) + ":" + stderr.String())
	}
	fmt.Println("Result: " + out.String())
	reader := bufio.NewReader(stdout)
	for {
		line, err2 := reader.ReadString('\n')
		if err2 != nil || io.EOF == err2 {
			break
		}
		fmt.Println(line)
	}
	//err := cmd.Start()
	//if err != nil {
	//	log.Fatal(err)
	//}
	err = cmd.Wait()
	if err != nil {
		log.Printf("Command finished with error: %v", err)
	}
	rt := out.String() //mahonia.NewDecoder("gbk").ConvertString(out.String()) //
	fmt.Println(rt)

	if strings.ContainsAny(rt, "成功") {
		fmt.Printf("{\"msg\":\"%s\"}", "操作成功")
	} else {
		fmt.Printf("{\"msg\":\"%s\"}", rt)
	}
	fmt.Print("结束\n")
	jishuqi += 1
	fmt.Println("计数器：", jishuqi)
	ch <- i
}

// 查找目录及子目录下的文件
// 添加参数判断
// path : 目标目录
// files : 容纳所有文件路径的结果数组
// targetType : 目标文件类型
// ignoreFile : 忽略文件（文件名，包括扩展名）
// ignorePath : 忽略目录
// ignoreType : 忽略文件类型
func GetAllFile(path string, files *[]string, ignorePath *[]string) (err error) {
	err = getAllFileRecursion(path, files, ignorePath)
	return err
}

// 递归查找目录及子目录下的文件
// path : 目标目录
// files : 容纳所有文件路径的结果数组
// targetType : 目标文件类型
// ignoreFile : 忽略文件（文件名，包括扩展名）
// ignorePath : 忽略目录
// ignoreType : 忽略文件类型
func getAllFileRecursion(path string, files *[]string, ignorePath *[]string) (err error) {
	l, err := ioutil.ReadDir(path)
	if err != nil {
		return err
	}
	separator := string(os.PathSeparator)
	for _, f := range l {
		tmp := string(path + separator + f.Name())
		if !hasGit(tmp) {
			if f.IsDir() {
				err = getAllFileRecursion(tmp, files, ignorePath)
				if err != nil {
					return err
				}
			}
		} else {
			*files = append(*files, tmp)
		}
	}

	return nil
}
func hasGit(path string) bool {
	var has bool
	dirList, e := ioutil.ReadDir(path)
	if e != nil {
		fmt.Println("read dir error")
		has = false
		return has
	}
	for _, v := range dirList {
		if v.Name() == ".git" {
			has = true
		}
	}
	return has

}

// 判断目标字符串是否是在数组中
func isInArray(list *[]string, s string) (isIn bool) {

	if len(*list) == 0 {
		return false
	}

	isIn = false
	for _, f := range *list {

		if f == s {
			isIn = true
			break
		}
	}

	return isIn
}

// 判断目标字符串的末尾是否含有数组中指定的字符串
func isInSuffix(list *[]string, s string) (isIn bool) {

	isIn = false
	for _, f := range *list {

		if strings.TrimSpace(f) != "" && strings.HasSuffix(s, f) {
			isIn = true
			break
		}
	}

	return isIn
}

// 判断数组各元素是否是空字符串或空格
func isAllEmpty(list *[]string) (isEmpty bool) {

	if len(*list) == 0 {
		return true
	}

	isEmpty = true
	for _, f := range *list {

		if strings.TrimSpace(f) != "" {
			isEmpty = false
			break
		}
	}

	return isEmpty
}
